#include <errno.h>
#include <myFs/blockbuf.h>
#include <myFs/simpleFShelper.h>
#include <spdlog/spdlog.h>
#include <string.h>
#include <sys/stat.h>

namespace myFs {
namespace basic {

using namespace spdlog;
using size_t = uint32_t;

SimpleFShelper::SimpleFShelper(::std::string dumpfile) : m_fsbasic(dumpfile) {
    info("SimpleFShelper construct");
    mknodHelper(m_fsbasic.getRootInum(), ".");
    mknodHelper(m_fsbasic.getRootInum(), "..");
}
SimpleFShelper::~SimpleFShelper() = default;
int SimpleFShelper::getattrHelper(size_t inum, Inode& inode) {
    debug("func={} inum={}", __func__, inum);
    if (inum == -1) {
        warn("func={} msg={}", __func__, "no found");
        return -1;
    }
    inode = m_fsbasic.toInode(inum);
    debug("func={} msg={}", __func__, "found");
    return 0;
}
int SimpleFShelper::openHelper(size_t inum) { return 0; }
int SimpleFShelper::writeHelper(size_t inum, char const* buf, size_t size, size_t off) {
    debug("func={} inum={}", __func__, inum);
    if (inum == -1) return -ENOENT;
    Buf blkbuf{m_fsbasic.toInode(inum), m_fsbasic.getBmap()};
    return blkbuf.write(buf, size, off);
}
int SimpleFShelper::readHelper(size_t inum, char* buf, size_t size, off_t off) {
    debug("func={} inum={}", __func__, inum);
    if (inum == -1) return -ENOENT;
    // debug("func={} msg={}", __func__, "get inode");
    Buf blkbuf{m_fsbasic.toInode(inum), m_fsbasic.getBmap()};
    return blkbuf.read(buf, size, off);
}
int SimpleFShelper::renameHelper(size_t pinum1, size_t inum1, size_t pinum2, std::string const& name2) {
    debug("func={} inum1={}, name1={}, inum2={}, name2={}", __func__, pinum1, inum1, pinum2, name2);
    removeDirEntry(pinum1, inum1);
    DirEntry de;
    strcpy(de.name, name2.data());
    de.inum = inum1;
    addDirEntry(pinum2, de);
    return 0;
}
int SimpleFShelper::rmdirHelper(size_t inum) {
    debug("func={} inum={} do nothing", __func__, inum);
    return 0;
}
size_t SimpleFShelper::mkdirHelper(size_t inum, std::string const& filename) {
    debug("func={} in inum={} mkdir filename={}", __func__, inum, filename);
    Buf      blkbuf{m_fsbasic.toInode(inum), m_fsbasic.getBmap()};
    DirEntry de;
    de.inum = m_fsbasic.getImap()->alloc(1);
    debug("func={} get unused inum={}", __func__, de.inum);
    m_fsbasic.initDirInode(de.inum);
    mknodHelper(de.inum, ".");
    mknodHelper(de.inum, "..");
    strcpy(de.name, filename.data());
    de.name[filename.size()] = 0;
    blkbuf.write((char*)(&de), sizeof(DirEntry), blkbuf.size());
    return 0;
}
size_t SimpleFShelper::mknodHelper(size_t inum, std::string const& filename) {
    debug("func={} mknod filename={} in inum={}", __func__, filename, inum);
    Buf      blkbuf{m_fsbasic.toInode(inum), m_fsbasic.getBmap()};
    DirEntry de;
    de.inum = m_fsbasic.getImap()->alloc(1);
    debug("func={} mknod {} inum={} in dir inum={}", __func__, filename, de.inum, inum);
    strcpy(de.name, filename.data());
    blkbuf.write((char*)(&de), sizeof(DirEntry), blkbuf.size());
    m_fsbasic.initFileInode(de.inum);
    return 0;
}

int SimpleFShelper::readdirHelper(size_t inum, std::vector<DirEntry>& dir) {
    // debug("func={} inum={}", __func__, inum);
    if (inum == -1) return -1;
    // debug("func={} msg={}", __func__, "get inode");
    Buf blkbuf{m_fsbasic.toInode(inum), m_fsbasic.getBmap()};
    // debug("func={} nbyte={}", __func__, nbyte);
    int n = blkbuf.size() / sizeof(DirEntry);
    // debug("func={} dir num={}", __func__, n);
    DirEntry de;
    size_t   off = 0;
    while (n--) {
        blkbuf.read((char*)(&de), sizeof(DirEntry), off);
        off += sizeof(DirEntry);
        debug("func={} dir name={}, dir inum={}", __func__, de.name, de.inum);
        dir.push_back(de);
    }
    // debug("func={} ret={}", __func__, 0);
    return 0;
}
int SimpleFShelper::unlinkHelper(size_t parentInum, size_t inum) {
    m_fsbasic.removeDirEntry(parentInum, inum);
    debug("func={} free inode", __func__);
    // nlink--, 检查nlink是否等于0，为0则释放inode的bnum, 释放inum
    m_fsbasic.freeInode(inum);
    return 0;
}
int SimpleFShelper::releasedirHelper(size_t inum) {
    //这个函数是有错误的，不能处理link问题
    if (inum == -1) return -ENOENT;
    // bfs
    //获得inum下目录
    std::vector<DirEntry> dir;
    readdirHelper(inum, dir);
    //获得目录下所有inum
    for (auto& de : dir) {
        Inode& inode = m_fsbasic.toInode(de.inum);
        if (inode.mode & S_IFDIR) {
            releasedirHelper(de.inum);
        } else {
            unlinkHelper(inum, de.inum);
        }
    }
    m_fsbasic.freeInode(inum);
    return 0;
}
size_t SimpleFShelper::toInum(std::string const& path) { return m_fsbasic.toInum(path); }

void SimpleFShelper::removeDirEntry(size_t pinum, size_t inum) { m_fsbasic.removeDirEntry(pinum, inum); }

void SimpleFShelper::addDirEntry(size_t pinum, DirEntry const& de) { m_fsbasic.addDirEntry(pinum, de); }
}  // namespace basic
}  // namespace myFs